// 通用接口
require("../models/relation")
require("./publicFn/asyncExits") // 公用的异步验证
const init = require("../util/init")
const publicFnInit = require("./publicFn/init")
const path = require("path")
const Alipay = require("alipay-sdk")
const AlipayFormData = require("alipay-sdk/lib/form")
const svgCaptcha = require("svg-captcha")
const fs = require('fs');
const https = require("https")
require('dotenv').config();
/**
 * 查询宿舍楼
 * @param {*} id 宿舍楼id
 * @param {*} classId 班级id
 */
exports.getDormitory = async function (id, classId) {
    const ralu = {
        id: {
            type: "number"
        },
        classId: {
            type: "number",
            classInfoExits: true
        }
    }
    try {
        await init.validate.async({
            id,
            classId
        }, ralu)
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    const res = await init.Dormitory.findAll({
        attributes: {
            exclude: ["createdAt", "updatedAt", "deletedAt"]
        },
        where: {
            id: id ? id : {
                [init.Op.not]: null
            }
        },
        include: [{
            attributes: ["id", "adminId", "Nickname", "phone", "avatar"],
            model: init.AdminInfon
        }, {
            attributes: ["id", "peopleNum", "price"],
            model: init.RoomRate
        }, {
            required: true,
            model: init.Floor,
            include: [{
                required: true,
                model: init.RoomNo,
                // classInfoId: classId ? classId : {[init.Op.not]: null}
                where: classId ? {
                    classInfoId: classId
                } : {}
            }]
        }]
    })
    const reslut = [];
    JSON.parse(JSON.stringify(res)).forEach(item => {
        reslut.push({
            id: item.id,
            DormitoryName: item.DormitoryName,
            floorNum: item.floorNum,
            roomNum: item.roomNum,
            fewPeople: item.fewPeople,
            dormitoryCapacity: item.dormitoryCapacity,
            dormitoryresided: item.dormitoryresided,
            AdminInfonId: item.AdminInfonId,
            RoomRateId: item.RoomRateId,
            AdminInfon: item.AdminInfon,
            RoomRate: item.RoomRate
        })
    });
    return reslut

}

/**
 * 查询楼层
 * @param {number} dormitoryId 宿舍楼id
 * @param {number} floorId 楼层id
 * @param {number} classId 班级id
 */
exports.floor = async function (Obj) {
    Obj = init.pick(Obj, "dormitoryId", "floorId", "classId")
    const rolu = {
        dormitoryId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            dormitoryIdExits: true
        },
        floorId: {
            type: "number",
            floorIdExits: true
        },
        classId: {
            type: "number",
            classInfoExits: true
        }
    }
    try {
        await init.validate.async(Obj, rolu)
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    const res = await init.Floor.findAll({
        attributes: ["id", "floorNumber", "roomNum", "floorCapacity", "floorResided"],
        where: {
            DormitoryId: Obj.dormitoryId,
            id: Obj.floorId ? Obj.floorId : {
                [init.Op.is]: !null
            }
        },
        include: [{
                attributes: ["id", "DormitoryName"],
                model: init.Dormitory,
            },
            {
                attributes: ["id", "cleaningName", "cleaningNumber", "avatar", "cleaningPhone"],
                model: init.Cleaning
            },
            {
                model: init.RoomNo,
                attributes: ["id", "roomNo"],
                where: Obj.classId ? {
                    classInfoId: Obj.classId
                } : {}
            }
        ]
    })
    return JSON.parse(JSON.stringify(res))
}

/**
 * 查询宿舍
 * @param {Object} Obj id对象
 * @param {*} Obj.dormitoryId 宿舍楼id
 * @param {*} Obj.floorId 楼层id
 * @param {number} Obj.roomNoId 宿舍id
 * @param {number} Obj.classId 班级id
 */
exports.roomNo = async function (Obj) {
    Obj = init.pick(Obj, "dormitoryId", "floorId", "roomNoId", "classId")
    const rolu = {
        dormitoryId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            dormitoryIdExits: true
        },
        floorId: {
            type: "number",
            floorIdExits: true
        },
        roomNoId: {
            type: "number",
            RoomNoExits: true
        },
        classId: {
            type: "number",
            classInfoExits: true
        }
    }
    try {
        await init.validate.async(Obj, rolu)
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    const where = {}
    if (Obj.floorId) {
        where.FloorId = Obj.floorId
    }
    if (Obj.roomNoId) {
        where.id = Obj.roomNoId
    }
    if (Obj.classId) {
        where.classInfoId = Obj.classId
    }

    const res = await init.RoomNo.findAll({
        attributes: ["id", "roomNo", "roomCapacity", "roomResided"],
        where,
        include: [{
                attributes: ["id", "floorNumber"],
                model: init.Floor,
                where: {
                    DormitoryId: Obj.dormitoryId
                }
            },
            {
                attributes: ["id", "bednumberId"],
                model: init.Bednumber,
                include: [{
                    attributes: ["id", "studentId", "Nickname", "phone", "checkInTime", "avatar"],
                    model: init.StudentSInfon
                }]
            },
        ]
    })
    const reslut = JSON.parse(JSON.stringify(res)).map(item => {
        return {
            id: item.id,
            roomNo: item.roomNo,
            roomCapacity: item.roomCapacity,
            roomResided: item.roomResided,
            Floor: {
                floorId: item.Floor.id,
                floorNumber: item.Floor.floorNumber
            },
            movingInStudents: item.Bednumbers.filter(i => {
                return i.StudentSInfon
            }).map(i => {
                return {
                    id: i.StudentSInfon.id,
                    studentName: i.StudentSInfon.Nickname,
                    studentID: i.StudentSInfon.studentId,
                    studentPhone: i.StudentSInfon.phone,
                    studentCheckInTime: i.StudentSInfon.checkInTime,
                    studentBed: i.bednumberId,
                    avatar: i.StudentSInfon.avatar
                }
            })
        }
    })
    if (reslut.length !== 0) {
        return reslut
    }
    throw "dormitoryId and floorId No association"

}




/**
 * 查询床号
 * @param {*} roomNoId 宿舍id
 * @param {number} bednumberId 床位id
 */

exports.bednumber = async function ({
    roomNoId,
    bednumberId
}) {
    const ralu = {
        roomNoId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            RoomNoExits: true
        },
        bednumberId: {
            type: "number",
            bednumberExits: true
        }
    }

    try {
        await init.validate.async({
            roomNoId
        }, ralu)
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    const res = await init.Bednumber.findAll({
        attributes: ["id", "bednumberId", "isPeople"],
        where: {
            RoomNoId: roomNoId,
            id: bednumberId ? bednumberId : {
                [init.Op.is]: !null
            }
        },
        include: [{
                attributes: ["id", "roomNo"],
                model: init.RoomNo
            },
            {
                attributes: ["id", "studentId", "Nickname", "phone", "avatar", "checkInTime"],
                model: init.StudentSInfon
            }
        ]
    })
    return JSON.parse(JSON.stringify(res))


}

/**
 * 头像上传
 * @returns {Object} 配置对象
 */

exports.upload = async function (file, callback) {
    let toFilename = null
    let filename = null
    if (file) {
        const ext = path.extname(file.originalname)
        const imgArr = [".png", ".webp", ".jpg"]
        if (!imgArr.includes(ext)) {
            return {
                code: "401",
                err: "Format is .png,.webp,.jpg"
            }
        }
        if (file.size > 1024 * 1024 * 5) {
            return {
                code: "401",
                err: "Exceeded memory size"
            }
        }

        const timeStap = Date.now()
        const ramdoms = Math.random().toString(36).slice(-6)

        filename = `${timeStap}${ramdoms}${ext}`
        toFilename = path.resolve(__dirname, '../public/upload/', filename)
    }
    let res = null
    try {
        res = await callback(filename)
    } catch (err) {
        return err
    }
    if (toFilename) {
        await fs.promises.writeFile(toFilename, file.buffer);
    }
    return res
}







/**
 * 验证订单是否支付
 * @param {*} Order 订单号
 * @param {*} callback 回调函数
 */
exports.whetherToPay = async function (Order, callback) {
    const alipay = new Alipay({
        appId: process.env.APPID,
        privateKey: process.env.PRIVATEKEY,
        alipayPublicKey: process.env.ALIPAYPUBLICKEY,
        gateway: process.env.GATEWAY,
    })
    const formData = new AlipayFormData();
    formData.setMethod('get');
    const bizContent = {
        out_trade_no: Order, // 商户订单号
    };
    formData.addField("bizContent", bizContent);
    const result = await alipay.exec("alipay.trade.query", {}, {
        formData
    });
    https.get(result, (resp => {
        let data = ""
        resp.on("data", chunk => {
            data += chunk
        })
        resp.on("end", () => {
            const res = {}
            if (!JSON.parse(data).alipay_trade_query_response.trade_status) {
                res.code = 4004;
                res.text = "未扫码"
            } else if (JSON.parse(data).alipay_trade_query_response.trade_status === "WAIT_BUYER_PAY") {
                res.code = 4003;
                res.text = "已扫码，未付款"
            } else if (JSON.parse(data).alipay_trade_query_response.trade_status === "TRADE_CLOSED") {
                res.code = 4002;
                res.text = "超时"
            } else if (JSON.parse(data).alipay_trade_query_response.trade_status === "TRADE_SUCCESS") {
                res.code = 4000;
                res.text = "交易成功"
            }
            callback(res)
        })
    }));
}

/**
 * 获取评论
 * @param {Number} page 页码
 * @param {Number} limit 一页多少条
 * @param {Number} roomNoId 宿舍id
 */
exports.getEvaluate = async function (page = 1, limit = 10, roomNoId) {
    const ralu = {
        page: {
            type: "number"
        },
        limit: {
            type: "number"
        },
        roomNoId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            RoomNoExits: true
        }
    }
    try {
        await init.validate.async({
            page,
            limit,
            roomNoId
        }, ralu)
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    const res = await init.Comment.findAndCountAll({
        attributes: ["id", "fraction", "comment", "time"],
        where: {
            RoomNoId: roomNoId
        },
        order: [
            ["time", "DESC"]
        ],
        offset: (page - 1) * limit,
        limit,
        include: [{
                attributes: ["id", "Nickname", "adminId", "avatar"],
                model: init.AdminInfon
            },
            {
                attributes: ["id", "roomNo"],
                model: init.RoomNo
            }
        ]
    })
    let reslut = {};
    reslut.total = JSON.parse(JSON.stringify(res)).count,
        reslut.rows = JSON.parse(JSON.stringify(res)).rows.map(itme => {
            return {
                id: itme.id,
                fraction: itme.fraction,
                comment: itme.comment,
                time: itme.time,
                roomNoId: itme.RoomNo.id,
                roomNo: itme.RoomNo.roomNo,
                adminId: itme.AdminInfon ? itme.AdminInfon.id : "",
                admin: itme.AdminInfon ? itme.AdminInfon.adminId : "",
                nickName: itme.AdminInfon ? itme.AdminInfon.Nickname : "",
                avatar: itme.AdminInfon ? itme.AdminInfon.avatar : ""
            }
        })
    return reslut

}


/**
 * 获取维修记录
 * @param {string} startTime 起始时间
 * @param {string} endTime 终止时间
 * @param {Array} dormitroyId 宿舍楼id
 * @param {number} floorId 楼层id
 * @param {number} roomId 宿舍id
 * @param {number} isHandle 是否处理(1. 处理 2.未处理) 
 */
exports.getMainRecords = async function (conditionObj) {
    conditionObj = init.pick(conditionObj, "startTime", "endTime", "dormitroyId", "floorId", "roomId", "isHandle", "page", "limit")
    const ralu = {
        startTime: {
            type: "string",
        },
        endTime: {
            type: "string",
        },
        dormitroyId: {
            type: "array",
            dormitoryIdArrExits: true
        },
        floorId: {
            type: "number",
            floorIdExits: true
        },
        roomId: {
            type: "number",
            RoomNoExits: true
        },
        isHandle: {
            type: "number",
            inclusion: [2, 1, 0]
        },
        page: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            numericality: {
                onlyInteger: true,
                greaterThan: 0,
            }
        },
        limit: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            numericality: {
                onlyInteger: true,
                greaterThan: 0,
            }
        }
    }
    try {
        await init.validate.async(conditionObj, ralu)
    } catch (err) {
        console.log(err);
        return {
            code: 401,
            err
        }
    }
    console.log(conditionObj);
    let isHandle = {}
    if (conditionObj.isHandle === 1) {
        isHandle = {
            RepairEndTime:{[init.Op.not]: null}
        }
    } else if (conditionObj.isHandle === 2) {
        isHandle = {
            RepairEndTime:{[init.Op.is]: null}
        }
    }

    const res = await init.RepairReport.findAndCountAll({
        offset: (conditionObj.page - 1) * conditionObj.limit,
        limit: conditionObj.limit,
        attributes: ["id", "RepairDescription", "RepairImg", "RepairStartTime", "RepairEndTime", "RepairEndImg", "RepariDormitroy", "RepariFloor","RepariRoomNo"],
        order: [
            ['RepairStartTime', 'DESC']
        ],
        where: {
            ...isHandle,
            RoomNoId: conditionObj.roomId || {
                [init.Op.not]: null
            },
            RepairStartTime: {
                [init.Op.gt]: conditionObj.startTime || 0,
                [init.Op.lt]: conditionObj.endTime || +init.moment.utc(),
            },
        },
        include: [{
            required:true,
            model: init.RoomNo,
            include: [{
                required:true,
                model: init.Floor,
                where:{
                    id: conditionObj.floorId || {
                        [init.Op.not]: null
                    },
                },
                include: [{
                    required:true,
                    model: init.Dormitory,
                    where: {
                        id: {
                            [init.Op.in]: conditionObj.dormitroyId
                        }
                    }
                }]
            }]
        }]
    })
    const reslut = {};
    reslut.count= JSON.parse(JSON.stringify(res)).count
    reslut.rows = JSON.parse(JSON.stringify(res)).rows.map(item => {
        return {
            id: item.id,
            RepairDescription: item.RepairDescription,
            RepairImg: item.RepairImg,
            RepairStartTime: item.RepairStartTime,
            RepariDormitroy: item.RepariDormitroy,
            RepariFloor: item.RepariFloor,
            RepariRoomNo: item.RepariRoomNo,
            RepairEndTime: item.RepairEndTime,
            RepairEndImg: item.RepairEndImg

        }
    })
    return reslut;
}